Daemon-backed chat backend (ffp_chat) + chat actions#20
Conversation
First step of moving chat into the web dashboard (retiring the tkinter popup).
New scripts/ffp_chat.py owns:
- thread storage reusing the existing data/chat_threads.jsonl format (popup-era
threads carry over): list/get/delete + compact atomic save,
- send(thread_id, message, use_notes) — appends the turn, optionally grounds in
the notes vault (ported build_notes_context_message/retrieve_notes_context),
calls the provider-resolved /v1/chat/completions (grammar_fix FLM_BASE_URL/
FLM_MODEL/LLM_AUTH_BEARER so chat follows the same FLM/Ollama selection),
persists, and returns {thread_id, title, reply, notes_used}. LLM call is
injectable for tests; blocking (no streaming) to match current behavior,
- stage/take selection (read-and-clear) backing the Ctrl+Shift+A prefill.
New daemon actions: chat_threads_list, chat_thread_get, chat_send [W],
chat_thread_delete [W], chat_stage_selection [W], chat_take_staged [W].
Registered ffp_chat in pyproject py-modules + the PyInstaller spec hiddenimports.
No UI yet and the popup is untouched — web Chat tab (next PR) consumes these;
the popup is retired in a later PR. 14 new ffp_chat tests; daemon action-count
test updated (53 -> 59). Full suite 194 green, ruff clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8be9e0b0c5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "cycle_tone_preset", "set_tone", "set_tone_formal", "set_tone_casual", "set_tone_friendly", | ||
| "pull_model", "remove_model", "apply_config_patch", "update_apply", | ||
| "set_autostart", "bench_start", "pull_start", | ||
| "chat_send", "chat_thread_delete", "chat_stage_selection", "chat_take_staged", |
There was a problem hiding this comment.
Avoid holding the write lock during chat completions
Because chat_send is now in _WRITE_ACTIONS, Handler.do_POST runs the entire handler under _write_lock; ffp_chat.send() performs the blocking LLM request before saving the thread, so a slow or timed-out model call can hold the daemon's write lock for the provider timeout and block unrelated write actions such as chat_stage_selection, chat_take_staged, and apply_config_patch. Please keep the lock scoped to the thread-store mutation instead of the whole completion request.
Useful? React with 👍 / 👎.
PR 1 of the chat→web work (retiring the tkinter popup). Adds
scripts/ffp_chat.py:data/chat_threads.jsonl(popup-era threads carry over).send(thread_id, message, use_notes)— optional notes-vault grounding, calls theprovider-resolved
/v1/chat/completions(via grammar_fix globals, so chat followsthe same FLM/Ollama selection as grammar/notes), persists, returns
{thread_id,title,reply,notes_used}. LLM call injectable for tests; blocking.New daemon actions:
chat_threads_list,chat_thread_get,chat_send[W],chat_thread_delete[W],chat_stage_selection[W],chat_take_staged[W].Registered in pyproject py-modules + PyInstaller spec hiddenimports.
No UI and the popup is untouched (web Chat tab + popup retirement land in later PRs).
14 new tests; daemon action-count test 53→59. Suite 194 green, ruff clean.